From b0a8440dd074844d5e27279fa05a7bbd109fb8e3 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Wed, 24 Nov 2004 18:22:22 +0000 Subject: [PATCH] bitkeeper revision 1.1159.187.6 (41a4d15eNLlT3wCGjZ2RZQx7hDushg) Behave properly with grows-down data segments. Maybe some cleaning up and merging with Michael Fetterman's patches required. :-) --- xen/arch/x86/x86_32/mm.c | 40 +++++++++++++++++++++++++-------- xen/arch/x86/x86_32/seg_fixup.c | 9 ++++---- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index d9a0414d2e..d90a60c520 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -190,16 +190,38 @@ int check_descriptor(unsigned long *d) limit++; /* We add one because limit is inclusive. */ if ( (b & _SEGMENT_G) ) limit <<= 12; - if ( ((base + limit) <= base) || - ((base + limit) > PAGE_OFFSET) ) + + if ( (b & (3<<10)) == 1 ) + { + /* + * Grows-down limit check. + * NB. limit == 0xFFFFF provides no access (if G=1). + * limit == 0x00000 provides 4GB-4kB access (if G=1). + */ + if ( (base + limit) > base ) + { + limit = -(base & PAGE_MASK); + goto truncate; + } + } + else { - /* Need to truncate. Calculate and poke a best-effort limit. */ - limit = PAGE_OFFSET - base; - if ( (b & _SEGMENT_G) ) - limit >>= 12; - limit--; - d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff; - d[1] &= ~0xf0000; d[1] |= limit & 0xf0000; + /* + * Grows-up limit check. + * NB. limit == 0xFFFFF provides 4GB access (if G=1). + * limit == 0x00000 provides 4kB access (if G=1). + */ + if ( ((base + limit) <= base) || + ((base + limit) > PAGE_OFFSET) ) + { + limit = PAGE_OFFSET - base; + truncate: + if ( !(b & _SEGMENT_G) ) + goto bad; /* too dangerous; too hard to work out... */ + limit = (limit >> 12) - 1; + d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff; + d[1] &= ~0xf0000; d[1] |= limit & 0xf0000; + } } good: diff --git a/xen/arch/x86/x86_32/seg_fixup.c b/xen/arch/x86/x86_32/seg_fixup.c index dc8e760020..85d7d75def 100644 --- a/xen/arch/x86/x86_32/seg_fixup.c +++ b/xen/arch/x86/x86_32/seg_fixup.c @@ -225,8 +225,7 @@ int fixup_seg(u16 seg, int positive_access) if ( ((base + limit) < PAGE_SIZE) && positive_access ) { /* Flip to expands-up. */ - limit >>= 12; - limit -= (-PAGE_OFFSET/PAGE_SIZE) + 2; + limit = PAGE_OFFSET - base; goto flip; } } @@ -236,8 +235,7 @@ int fixup_seg(u16 seg, int positive_access) if ( ((PAGE_OFFSET - (base + limit)) < PAGE_SIZE) && !positive_access ) { /* Flip to expands-down. */ - limit >>= 12; - limit += (-PAGE_OFFSET/PAGE_SIZE) + 0; + limit = -(base & PAGE_MASK); goto flip; } } @@ -249,9 +247,10 @@ int fixup_seg(u16 seg, int positive_access) return 0; flip: + limit = (limit >> 12) - 1; a &= ~0x0ffff; a |= limit & 0x0ffff; b &= ~0xf0000; b |= limit & 0xf0000; - b ^= 1 << 10; + b ^= 1 << 10; /* grows-up <-> grows-down */ /* NB. These can't fault. Checked readable above; must also be writable. */ table[2*idx+0] = a; table[2*idx+1] = b; -- 2.30.2